#include "multiset_mt.h"

#include <bool.h>
#include <bstring.h>
#include <colorset.h>
#include <dynamictypemanager.h>
#include <multiset.h>
#include <number.h>
#include <typefactory.h>
#include <wfnet.h>

#include <QtTest/QTest>

using namespace wfnet;
using namespace moduletest;

void Multiset_mt::initTestCase()
{
    EnumerationValues vals;
    vals << "black" << "red" << "blue";
    Enumeration colors("EColors", vals);

    TypeFactory::getInstance()->registerType(colors);

    m_net = new WfNet(this);

    DynamicTypeManager::getInstance()->registerColorSet("Colors",
        colors, m_net);
    DynamicTypeManager::getInstance()->registerColorSet("Bools",
        Bool(), m_net);
    DynamicTypeManager::getInstance()->registerColorSet("Strings",
        BasicString(), m_net);
    DynamicTypeManager::getInstance()->registerColorSet("Numbers",
        Number(), m_net);
}

void Multiset_mt::constructor()
{
    QFETCH(bool, value);
    QFETCH(bool, result);

    QCOMPARE(value, result);
}

void Multiset_mt::constructor_data()
{
    const TypeValue colorsValue = "{2*$black$ + 1*$red$ + 4*$blue$}";
    const TypeValue boolsValue = "{2*true + 1*false + 4*false}";
    const TypeValue stringsValue =
        "{2*\"COLORED\" + 1*\"PETRI\" + 4*\"NETS\"}";
    const TypeValue numbersValue = "{2*10 + 1*15 + 4*1}";
    const TypeValue numbersValue1 = "{2*10}";

    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    c.setValue("blue");
    ColorSet b = *DynamicTypeManager::getInstance()->getColorSet("Bools",
        m_net);
    b.setValue(false);
    ColorSet s = *DynamicTypeManager::getInstance()->getColorSet("Strings",
        m_net);
    s.setValue("NETS");
    ColorSet n = *DynamicTypeManager::getInstance()->getColorSet("Numbers",
        m_net);
    n.setValue(10);

    Multiset cMs("Colors", colorsValue);
    Multiset bMs("Bools", boolsValue);
    Multiset sMs("Strings", stringsValue);
    Multiset nMs("Numbers", numbersValue);
    Multiset n1Ms("Numbers", numbersValue1);

    Multiset sNVms("Strings", boolsValue);
    Multiset cNVms("Colors", "{1*$orange$}");
    Multiset gNVMs("Numbers", "");
    Multiset g1NVMs("Numbers", "{}");
    Multiset g2NVMs("Numbers", "{2*10");
    Multiset g3NVMs("Numbers", "2*10}");
    Multiset g4NVMs("Numbers", "{2*10 / 1*15}");
    Multiset g5NVMs("Numbers", "{2x10 + 1*15}");
    Multiset g6NVMs("Numbers", "{2*10 1*15}");
    Multiset g7NVMs("Numbers", "{2*10 + 1*$black$}");
    Multiset g8NVMs("Numbers", "{10 + 1*15}");

    QTest::addColumn<bool>("value");
    QTest::addColumn<bool>("result");

    QTest::newRow("Valid Colors") << (!cMs.isEmpty() &&
        cMs.coefficient(c) == 4) << true;
    QTest::newRow("Valid Bools") << (!bMs.isEmpty() &&
        bMs.coefficient(b) == 5) << true;
    QTest::newRow("Valid Strings") << (!sMs.isEmpty() &&
        sMs.coefficient(s) == 4) << true;
    QTest::newRow("Valid Numbers") << (!nMs.isEmpty() &&
        nMs.coefficient(n) == 2) << true;
    QTest::newRow("Valid Numbers1") << (!n1Ms.isEmpty()) << true;

    QTest::newRow("Not Valid") << sNVms.isEmpty() << true;
    QTest::newRow("Not Valid") << cNVms.isEmpty() << true;
    QTest::newRow("Not Valid") << gNVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g1NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g2NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g3NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g4NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g5NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g6NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g7NVMs.isEmpty() << true;
    QTest::newRow("Not Valid") << g8NVMs.isEmpty() << true;
}

void Multiset_mt::name()
{
    Multiset cMs("Colors");
    Multiset bMs("Bools");
    Multiset sMs("Strings");
    Multiset nMs("Numbers");

    QString nameMask = "%1_%2";

    QVERIFY(cMs.name() == nameMask.arg(Multiset::NAME).arg("Colors"));
    QVERIFY(bMs.name() == nameMask.arg(Multiset::NAME).arg("Bools"));
    QVERIFY(sMs.name() == nameMask.arg(Multiset::NAME).arg("Strings"));
    QVERIFY(nMs.name() == nameMask.arg(Multiset::NAME).arg("Numbers"));
}

void Multiset_mt::matches()
{
    QFETCH(bool, value);
    QFETCH(bool, result);

    QCOMPARE(value, result);
}

void Multiset_mt::matches_data()
{
    Multiset cMs("Colors");
    Multiset c1Ms("Colors");
    Multiset bMs("Bools");
    Multiset b1Ms("Bools");
    Multiset sMs("Strings");
    Multiset s1Ms("Strings");
    Multiset nMs("Numbers");
    Multiset n1Ms("Numbers");

    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet b = *DynamicTypeManager::getInstance()->getColorSet("Bools",
        m_net);
    ColorSet s = *DynamicTypeManager::getInstance()->getColorSet("Strings",
        m_net);
    ColorSet n = *DynamicTypeManager::getInstance()->getColorSet("Numbers",
        m_net);

    QTest::addColumn<bool>("value");
    QTest::addColumn<bool>("result");

    QTest::newRow("Valid Colors") << (cMs.matches(c1Ms) && cMs.matches(c) &&
        cMs.matches("Colors") && cMs.matches(Multiset::NAME)) << true;
    QTest::newRow("Valid Bools") << (bMs.matches(b1Ms) && bMs.matches(b) &&
        bMs.matches("Bools") && bMs.matches(Multiset::NAME)) << true;
    QTest::newRow("Valid Strings") << (sMs.matches(s1Ms) && sMs.matches(s) &&
        sMs.matches("Strings") && sMs.matches(Multiset::NAME)) << true;
    QTest::newRow("Valid Numbers") << (nMs.matches(n1Ms) && nMs.matches(n) &&
        nMs.matches("Numbers") && nMs.matches(Multiset::NAME)) << true;
}

void Multiset_mt::canConvert()
{
    QFETCH(bool, value);
    QFETCH(bool, result);

    QCOMPARE(value, result);
}

void Multiset_mt::canConvert_data()
{
    const TypeValue colorsValue = "{2*$black$ + 1*$red$ + 4*$blue$}";
    const TypeValue boolsValue = "{2*true + 1*false + 4*false}";
    const TypeValue stringsValue =
        "{2*\"COLORED\" + 1*\"PETRI\" + 4*\"NETS\"}";
    const TypeValue numbersValue = "{2*10 + 1*15 + 4*1}";
    const TypeValue numbersValue1 = "{2*10}";

    Multiset cMs("Colors", colorsValue);
    Multiset bMs("Bools", boolsValue);
    Multiset sMs("Strings", stringsValue);
    Multiset nMs("Numbers", numbersValue);

    QTest::addColumn<bool>("value");
    QTest::addColumn<bool>("result");

    QTest::newRow("Valid Colors") << cMs.canConvert(colorsValue) << true;
    QTest::newRow("Valid Bools") << bMs.canConvert(boolsValue) << true;
    QTest::newRow("Valid Strings") << sMs.canConvert(stringsValue) << true;
    QTest::newRow("Valid Numbers") << nMs.canConvert(numbersValue) << true;
    QTest::newRow("Valid Numbers1") << nMs.canConvert(numbersValue1) << true;

    QTest::newRow("Not Valid") << sMs.canConvert(boolsValue) << false;
    QTest::newRow("Not Valid") << cMs.canConvert("{1*$orange$}") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{}") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{2*10") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("2*10}") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{2*10 / 1*15}") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{2x10 + 1*15}") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{2*10 1*15}") << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{2*10 + 1*$black$}")
        << false;
    QTest::newRow("Not Valid") << nMs.canConvert("{10 + 1*15}") << false;
}

void Multiset_mt::isEmpty()
{
    Multiset ms("Colors");
    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    c.setValue("black");

    bool isEmpty = ms.isEmpty();
    QVERIFY(isEmpty);
    ms.insert(c);
    isEmpty = !ms.isEmpty();
    QVERIFY(isEmpty);
    ms.remove(c);
    isEmpty = ms.isEmpty();
    QVERIFY(isEmpty);
}

void Multiset_mt::contains()
{
    Multiset ms("Colors");
    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    c.setValue("black");

    QVERIFY(!ms.contains(c));
    ms.insert(c);
    QVERIFY(ms.contains(c));
}

void Multiset_mt::size()
{
    QFETCH(uint, value);
    QFETCH(uint, result);

    QCOMPARE(value, result);
}

void Multiset_mt::size_data()
{
    const uint first_size = 0;
    const uint second_size = 2;
    const uint third_size = 0;

    Multiset ms("Colors");
    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    c.setValue("black");

    QTest::addColumn<uint>("value");
    QTest::addColumn<uint>("result");

    QTest::newRow("Zero size") << ms.coefficient(c) << first_size;
    ms.insert(c);
    ms.insert(c);
    QTest::newRow("Size == 2") << ms.coefficient(c) << second_size;
    ms.remove(c);
    ms.remove(c);
    QTest::newRow("Size == 0 again") << ms.coefficient(c) << third_size;
}

void Multiset_mt::insert()
{
    Multiset ms("Colors");
    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    c.setValue("black");

    QVERIFY(!ms.contains(c));
    ms.insert(c);
    QVERIFY(ms.contains(c));
}

void Multiset_mt::remove()
{
    Multiset ms("Colors");
    ColorSet c = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    c.setValue("black");

    ms.insert(c);
    QVERIFY(ms.contains(c));
    ms.remove(c);
    QVERIFY(!ms.contains(c));
}

void Multiset_mt::operatorPlus()
{
    QFETCH(uint, value);
    QFETCH(uint, result);

    QCOMPARE(value, result);
}

void Multiset_mt::operatorPlus_data()
{
    const uint first_color_size = 2;
    const uint second_color_size = 3;
    const uint third_color_size = 1;

    Multiset ms1("Colors"), ms2("Colors"), msRes("Colors");
    ColorSet c1 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c2 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c3 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);

    c1.setValue("black");
    c2.setValue("red");
    c3.setValue("blue");

    ms1.insert(c1);
    ms1.insert(c2);
    ms1.insert(c2);
    ms2.insert(c1);
    ms2.insert(c2);
    ms2.insert(c3);

    msRes = ms1 + ms2;

    QTest::addColumn<uint>("value");
    QTest::addColumn<uint>("result");

    QTest::newRow("Size == 2") << msRes.coefficient(c1) << first_color_size;
    QTest::newRow("Size == 3") << msRes.coefficient(c2) << second_color_size;
    QTest::newRow("Size == 1") << msRes.coefficient(c3) << third_color_size;
}

void Multiset_mt::operatorMinus()
{
    QFETCH(uint, value);
    QFETCH(uint, result);

    QCOMPARE(value, result);
}

void Multiset_mt::operatorMinus_data()
{
    const uint first_color_size = 2;
    const uint second_color_size = 1;
    const uint third_color_size = 0;
    const uint not_valid_sub_size = 0;

    Multiset ms1("Colors"), ms2("Colors"), msRes("Colors");
    ColorSet c1 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c2 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c3 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);

    c1.setValue("black");
    c2.setValue("red");
    c3.setValue("blue");

    ms1.insert(c1);
    ms1.insert(c2);
    ms1.insert(c2);
    ms2.insert(c1);
    ms2.insert(c2);
    ms2.insert(c3);

    msRes = ms1 - ms2;

    QTest::addColumn<uint>("value");
    QTest::addColumn<uint>("result");

    QTest::newRow("NOT VALID Size == 0") << msRes.coefficient(c1) << not_valid_sub_size;
    QTest::newRow("NOT VALID Size == 0") << msRes.coefficient(c2) << not_valid_sub_size;
    QTest::newRow("NOT VALID Size == 0") << msRes.coefficient(c3) << not_valid_sub_size;

    ms1.insert(c1);
    ms1.insert(c1);
    ms2.remove(c3);

    msRes = ms1 - ms2;

    QTest::newRow("Size == 2") << msRes.coefficient(c1) << first_color_size;
    QTest::newRow("Size == 1") << msRes.coefficient(c2) << second_color_size;
    QTest::newRow("Size == 0") << msRes.coefficient(c3) << third_color_size;
}

void Multiset_mt::operatorMultiple()
{
    QFETCH(uint, value);
    QFETCH(uint, result);

    QCOMPARE(value, result);
}

void Multiset_mt::operatorMultiple_data()
{
    const uint first_color_size = 2;
    const uint second_color_size = 4;
    const uint third_color_size = 0;

    const uint multiplier = 2;

    Multiset ms1("Colors"), msRes("Colors");
    ColorSet c1 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c2 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c3 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);

    c1.setValue("black");
    c2.setValue("red");
    c3.setValue("blue");

    ms1.insert(c1);
    ms1.insert(c2);
    ms1.insert(c2);

    msRes = ms1 * multiplier;

    QTest::addColumn<uint>("value");
    QTest::addColumn<uint>("result");

    QTest::newRow("Size == 2") << msRes.coefficient(c1) << first_color_size;
    QTest::newRow("Size == 4") << msRes.coefficient(c2) << second_color_size;
    QTest::newRow("Size == 0") << msRes.coefficient(c3) << third_color_size;
}

void Multiset_mt::operatorLessEqual()
{
    Multiset ms1("Colors"), ms2("Colors");
    ColorSet c1 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c2 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);
    ColorSet c3 = *DynamicTypeManager::getInstance()->getColorSet("Colors",
        m_net);

    c1.setValue("black");
    c2.setValue("red");
    c3.setValue("blue");

    ms1.insert(c1);
    ms1.insert(c2);
    ms2.insert(c1);
    ms2.insert(c2);
    ms2.insert(c3);

    QVERIFY(ms1 <= ms2);
    QVERIFY(!(ms2 <= ms1));

    ms1.insert(c1);
    ms1.insert(c3);
    ms2.remove(c3);

    QVERIFY(ms2 <= ms1);
    QVERIFY(!(ms1 <= ms2));
}

void Multiset_mt::cleanupTestCase()
{
    DynamicTypeManager::getInstance()->unregisterColorSet("Colors",
        m_net);
    DynamicTypeManager::getInstance()->unregisterColorSet("Bools",
        m_net);
    DynamicTypeManager::getInstance()->unregisterColorSet("Strings",
        m_net);
    DynamicTypeManager::getInstance()->unregisterColorSet("Numbers",
        m_net);
}
